<template>
	<view class="">
		<view class="">
			<scroll-view class="scroll_x" :style="[{ background: bgColor }]" scroll-x :scroll-left="scroll_left"
				scroll-with-animation>
				<view class="menu">
					<view class="menu_name">
						<view class="flex1 menu_item"
							:style="[{ transition: `${duration}ms` }, current == index ? activeStyle : inactiveStyle]"
							v-for="(item, index) in tabs_list" :key="index" @click="clickTabs(index)">
							{{ item[keyName] }}
						</view>
					</view>
					<view class="menu_mark" v-if="box_data.length > 0"
						:style="[{ '--mark_left': `${box_data[current].mark}px` }, { transition: `${duration}ms` }, lineStyle]">
					</view>
				</view>
			</scroll-view>
		</view>

		<view class="bgf">
			<scroll-view :scroll-top="scrollRightTop" class="cont_scroll" scroll-y scroll-with-animation
				:style="{ height:list_h?`${list_h}rpx`: `calc(100vh - ${nav_h}px - 88rpx)` }" @scroll="scroll">
				<view class="" :style="{ paddingBottom: `calc(100vh - ${nav_h}px - 200rpx)` }">
					<view class="list_item" :id="'item' + index" v-for="(item, index) in list" :key="index">
						<slot name="listItem" :row="item" :index='index'></slot>
					</view>
				</view>
			</scroll-view>
		</view>
	</view>
</template>

<script>
	/* @property {Boolean}  is_nav 是否自定义导航栏
	 * 滑动菜单，滑动菜单，自动计算滑块宽度，自动居中，支持自定义样式，高度自定义
	 * @property {Array}  tabs_list tabs标签数据
	 * @property {String} keyName 从tabs_list元素对象中读取的键名
	 * @property {Number} current 当前选中标签的索引
	 * @property {Number} duration 滑块移动一次所需的时间，单位ms
	 * @property {String} bgColor 标签区域的背景颜色
	 * @property {Number} lineWidth  选择中滑块的宽度(单位rpx)
	 * @property {Number} lineHeight  选择中滑块的高度(单位rpx)
	 * @property {String} lineColor  选择中滑块的颜色
	 * @property {Object} inactiveStyle  菜单未选择中时的样式
	 * @property {Object} activeStyle  菜单选择中时的样式
	 * 列表
	 * @property {Array}  list 列表数据
	 * @property {Number} list_h  滑动内容的高度(单位rpx)
	 */
	export default {
		props: {
			is_nav: {
				typeof: Boolean,
				default: () => false
			},
			tabs_list: {
				typeof: Array,
				default: () => []
			},
			keyName: {
				typeof: String,
				default: () => 'name'
			},
			current: {
				typeof: Number,
				default: () => 0
			},
			duration: {
				typeof: Number,
				default: () => 300
			},
			bgColor: {
				typeof: String,
				default: () => '#fff'
			},
			lineWidth: {
				typeof: Number,
				default: () => 40
			},
			lineHeight: {
				typeof: Number,
				default: () => 6
			},
			lineColor: {
				typeof: String,
				default: () => '#3c9cff'
			},
			activeStyle: {
				typeof: Object,
				default: () => ({
					color: 'rgb(48, 49, 51)'
				})
			},
			inactiveStyle: {
				typeof: Object,
				default: () => {}
			},
			//列表
			list: {
				typeof: Array,
				default: () => []
			},
			list_h: {
				typeof: Number,
				default: () => ''
			},
		},
		data() {
			return {
				nav_h: 0, //顶部高度
				tabs_data: {
					left: 0,
					right: 0,
					top: 0,
					bottom: 0,
					width: 0,
					height: 0,
				}, //菜单数据
				scroll_left: 0, //横向滚动条位置
				box_data: [], //盒子数据

				scroll_top_arr: [], //左侧菜单距离登录距离列表
				scrollRightTop: 0 // 右边栏目scroll-view的滚动条高度
			};
		},
		async mounted() {
			this.nav_h = await this.getH();
			await this.updatePoses();
			await this.updatePosesList()
			await this.getMenuItemTop();
		},
		methods: {
			clickTabs(index, e) {
				if (index == this.current && !e) return;
				this.$emit('update:current', index);
				this.scroll_left = this.box_data[index].left - this.tabs_data.width / 2 + this.box_data[index].width / 2;
				this.scrollRightTop = this.scroll_top_arr[index];
			},

			updatePoses() { //获取tabs盒子数据
				return new Promise((resolve) => {
					let query = uni.createSelectorQuery().in(this);
					query.select('.scroll_x').boundingClientRect((data) => {
						if (!data) {
							clearTimeout(this.settime)
							this.settime = setTimeout(() => {
								this.update_poses();
							}, 10);
							return;
						}
						this.tabs_data = data;
						resolve()
					}).exec();
				})
			},
			updatePosesList() { //获取tabs每项数组合集
				return new Promise((resolve) => {
					let query = uni.createSelectorQuery().in(this);
					let arr = [];
					query.selectAll('.menu_item').boundingClientRect((data) => {
						if (!data || data.length == 0) {
							clearTimeout(this.settime)
							this.settime = setTimeout(() => {
								this.updatePosesList();
							}, 10);
							return;
						}
						data.map((item) => {
							arr.push({
								width: item.width, //盒子的宽度
								left: item.left, //盒子距离左边的位置
								mark: (item.left + item.right) / 2 - this.tabs_data
									.left //滑块距离左边的位置
							});
						});
						this.box_data = arr;
						resolve()
					}).exec();
				})
			},
			// 获取右边菜单每个item到顶部的距离
			getMenuItemTop() {
				new Promise((resolve) => {
					let selectorQuery = uni.createSelectorQuery().in(this);
					selectorQuery.selectAll('.list_item').boundingClientRect((rects) => {
							// 如果节点尚未生成，rects值为[](因为用selectAll，所以返回的是数组)，循环调用执行
							if (!rects.length) {
								clearTimeout(this.settime)
								this.settime = setTimeout(() => {
									this.getMenuItemTop();
								}, 10);
								return;
							}
							rects.forEach((rect) => {
								// 这里减去rects[0].top，是因为第一项顶部可能不是贴到导航栏(比如有个搜索框的情况)
								this.scroll_top_arr.push(rect.top - rects[0].top);
								resolve();
							});
							this.clickTabs(this.current, true);
						})
						.exec();
				});
			},
			// 菜单滚动
			async scroll(e) {
				if (this.scroll_top_arr.length == 0) {
					await this.getMenuItemTop();
				}
				setTimeout(() => {
					// 节流
					let scrollHeight = e.detail.scrollTop + 4;
					this.scroll_top_arr.map((item, index) => {
						if (scrollHeight > item) {
							this.$emit('update:current', index);
							this.scroll_left = this.box_data[index].left - this.tabs_data.width / 2 +
								this.box_data[index].width / 2;
						}
					});
				}, 10);
			},
			getH() {
				//获取状态栏高度
				return new Promise((resolve, reject) => {
					uni.getSystemInfo({
						success: (e) => {
							let statusBar = 0; //状态栏高度
							let customBar = 0; // 状态栏高度 + 导航栏高度
							let navbar = 0; // 自定义标题与胶囊对齐高度

							// #ifdef MP
							statusBar = e.statusBarHeight;
							customBar = e.statusBarHeight + 46;
							if (e.platform === 'android') {
								customBar = e.statusBarHeight + 50;
							}
							// #endif

							// #ifdef MP-WEIXIN
							statusBar = e.statusBarHeight;
							const custom = wx.getMenuButtonBoundingClientRect();
							customBar = this.is_nav ? custom.bottom + custom.top - e.statusBarHeight +
								4 : 0;
							navbar = (custom.top - e.statusBarHeight) * 2 + custom.height;
							// #endif

							// #ifdef MP-ALIPAY
							statusBar = e.statusBarHeight;
							customBar = e.statusBarHeight + e.titleBarHeight;
							// #endif

							// #ifdef APP-PLUS
							// console.log('app-plus', e);
							statusBar = e.statusBarHeight;
							customBar = e.statusBarHeight + 44;
							// #endif

							// #ifdef H5
							statusBar = 0;
							customBar = e.statusBarHeight + 100;
							// #endif
							resolve(customBar);
						},
						fail: (err) => {
							reject(err);
						}
					});
				});
			}
		},
		computed: {
			lineStyle() {
				//滑块的样式
				return {
					width: `${this.lineWidth}rpx`,
					height: `${this.lineHeight}rpx`,
					background: this.lineColor
				};
			}
		},
		watch: {
			current: {
				async handler(news, old) {
					this.$emit('click', news);
				},
				deep: true
			}
		}
	};
</script>

<style lang="scss">
	.bgf {
		background-color: #fff;
	}

	.scroll_x {
		width: 100%;
		height: 88rpx;
		white-space: nowrap;

		.menu {
			position: relative;
			height: 100%;

			.menu_name {
				position: absolute;
				left: 0;
				top: 0;
				z-index: 99;
				width: 100%;
				height: 100%;
				display: flex;

				.menu_item {
					height: 100%;
					color: rgb(96, 98, 102);
					font-size: 28rpx;
					font-weight: 500;
					display: flex;
					align-items: center;
					justify-content: center;
					padding: 0 20rpx;
				}
			}

			.menu_mark {
				position: absolute;
				bottom: 0;
				left: var(--mark_left);
				transform: translate(-50%, -50%);
				border-radius: 20rpx;
			}
		}
	}
</style>